#include "modbus_rtu_slave.h"
#include "ui_modbus_rtu_slave.h"
#include <QModbusDataUnit>
#include <QSerialPort>
#include <QDebug>
#include <QMessageBox>
#include <QSerialPortInfo>
#include <QModbusServer>
#include <QModbusRtuSerialSlave>

modbus_rtu_slave::modbus_rtu_slave(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::modbus_rtu_slave)
{
    ui->setupUi(this);

    //初始化界面元素
    if (!modbusDevice) {
        setupModbusSlave();
    }

    setupRegistersTable();
    updateUiState(false);

    this->centralWidget()->setLayout(ui->verticalLayout);

}

modbus_rtu_slave::~modbus_rtu_slave()
{
    if (modbusDevice)
        modbusDevice->disconnectDevice();
    delete ui;
}

void modbus_rtu_slave::on_connectButton_clicked()
{
    if (modbusDevice->state() != QModbusDevice::ConnectedState) {
        modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, ui->portCombo->currentText());
        modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);
        modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, ui->baudCombo->currentText().toInt());
        modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, 8);
        modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, 1);

        modbusDevice->setServerAddress(ui->serverAddressSpin->value());

        if (!modbusDevice->connectDevice()) {
            QMessageBox::critical(this, tr("Error"), tr("Connect failed: ") + modbusDevice->errorString());
        } else {
            updateUiState(true);
        }
    } else {
        modbusDevice->disconnectDevice();
        updateUiState(false);
    }
}

//当模型中的数据被修改时，同步修改modbus寄存器的值
void modbus_rtu_slave::updateRegisterValue(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
    Q_UNUSED(bottomRight)

    if (!modbusDevice || modbusDevice->state() != QModbusDevice::ConnectedState)
        return;

    int row = topLeft.row();
    int column = topLeft.column();

    if (column == 3) { // 只有值列变化时才更新
        QModelIndex typeIndex = registersModel->index(row, 0);
        QModelIndex addrIndex = registersModel->index(row, 2);
        QModelIndex valueIndex = registersModel->index(row, 3);

        QString type = registersModel->data(typeIndex).toString();
        quint16 address = registersModel->data(addrIndex).toUInt();
        quint16 value = registersModel->data(valueIndex).toUInt();

        QModbusDataUnit::RegisterType regType;

        if (type == "Coil") {
            regType = QModbusDataUnit::Coils;
        } else if (type == "Discrete Input") {
            regType = QModbusDataUnit::DiscreteInputs;
        } else if (type == "Input Register") {
            regType = QModbusDataUnit::InputRegisters;
        } else if (type == "Holding Register") {
            regType = QModbusDataUnit::HoldingRegisters;
        } else {
            return; // 未知类型
        }

        // 创建一个包含单个寄存器的数据单元
        QModbusDataUnit unit(regType, address, 1);
        unit.setValue(0, value); // 设置新值

        // 正确设置数据到Modbus设备
        if (!modbusDevice->setData(unit)) {
            QMessageBox::warning(this, tr("Error"), tr("Could not set register value"));
        }
    }
}

void modbus_rtu_slave::handleDeviceError(QModbusDevice::Error error)
{
    if (error == QModbusDevice::NoError)
        return;

    QMessageBox::warning(this, tr("Device Error"), modbusDevice->errorString());
}

void modbus_rtu_slave::setupModbusSlave()
{
    modbusDevice = new QModbusRtuSerialSlave(this);
    connect(modbusDevice, &QModbusServer::errorOccurred, this, &modbus_rtu_slave::handleDeviceError);

    // 设置Modbus数据存储,每种类型寄存器10个数据
    QModbusDataUnitMap reg;
    reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
    reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
    reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
    reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });

    modbusDevice->setMap(reg);

    // 填充可用的串口
    ui->portCombo->clear();
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
        ui->portCombo->addItem(info.portName());
    }

    // 设置默认波特率
    ui->baudCombo->addItems({"9600", "19200", "38400", "57600", "115200"});
    ui->baudCombo->setCurrentText("9600");

    // 设置服务器地址范围
    ui->serverAddressSpin->setRange(1, 247);
}

void modbus_rtu_slave::setupRegistersTable()
{
    registersModel = new QStandardItemModel(0, 4, this);
    registersModel->setHorizontalHeaderLabels({"Type", "Active", "Address", "Value"});

    // 添加示例数据
    QStringList types = {"Coil", "Discrete Input", "Input Register", "Holding Register"};

    for (const QString &type : types) {
        for (int i = 0; i < 10; ++i) {
            QList<QStandardItem*> rowItems;
            rowItems << new QStandardItem(type);
            rowItems << new QStandardItem("Yes");
            rowItems << new QStandardItem(QString::number(i));
            rowItems << new QStandardItem(QString::number(0));
            registersModel->appendRow(rowItems);
        }
    }

    ui->registersTable->setModel(registersModel);
    ui->registersTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

    connect(registersModel, &QStandardItemModel::dataChanged,
            this, &modbus_rtu_slave::updateRegisterValue);
}

void modbus_rtu_slave::updateUiState(bool connected)
{
    ui->connectButton->setText(connected ? tr("Disconnect") : tr("Connect"));
    ui->portCombo->setEnabled(!connected);
    ui->baudCombo->setEnabled(!connected);
    ui->serverAddressSpin->setEnabled(!connected);
}